package cn.birdbaby.plugins.annotator.classannotator.gen;

import cn.birdbaby.plugins.annotator.classannotator.gen.genannotator.AnnotatorProcessor;
import cn.birdbaby.plugins.constants.Constants;
import cn.birdbaby.plugins.common.CommonUtils;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSet;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Processor;
import com.intellij.util.SequentialTask;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

/**
 * @author llorando 4/8/24 3:03 pm
 */
public class BBProcessingAddGenAnnotationsTask implements SequentialTask {
    //进度条
    private ProgressIndicator myProgressIndicator;
    //项目中的文件夹
    @NotNull
    private final Collection<? extends VirtualFile> myRoots;
    private int myTotalFiles;
    private int myFilesProcessed;
    private boolean myStopFormatting;
    private PsiFile next;

    private Project myProject;
    private Editor editor;

    private String groupId;

    private Application application;

    public boolean process() {
        //遍历文件，逐个删除gen注解
        return processAll(psiFile -> {
            //避免用户取消了，后台还一直在跑
            ProgressIndicatorProvider.checkCanceled();
            CommonUtils.processWithGroupId(myProject,groupId,() ->
                    new AnnotatorProcessor(psiFile, groupId, Constants.all).addGenAnnotation()
            );
            return true;
        });
    }

    public BBProcessingAddGenAnnotationsTask(ProgressIndicator indicator, Project myProject, Editor editor) {
        //对多个psFile进行操作的过程中，writeCommand使用同一个groupId，一次ctrl-z就能回退操作了
        this.groupId = UUID.randomUUID().toString();
        this.myProgressIndicator = indicator;
        this.editor = editor;
        this.myProject = myProject;
        this.application = ApplicationManager.getApplication();
        this.myRoots = ContainerUtil.<PsiDirectory, VirtualFile>map(collectProjectDirectories(myProject), psiDir -> psiDir.getVirtualFile());
    }

    static List<PsiDirectory> collectProjectDirectories(@NotNull Project project) {
        Module[] modules = ModuleManager.getInstance(project).getModules();
        List<PsiDirectory> directories = new ArrayList<>(modules.length * 3);
        for (Module module : modules) {
            directories.addAll(collectModuleDirectories(module));
        }

        return directories;
    }

    static List<PsiDirectory> collectModuleDirectories(Module module) {
        VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots();
        return ReadAction.compute(() -> ContainerUtil.mapNotNull(contentRoots, root -> PsiManager.getInstance(module.getProject()).findDirectory(root)));
    }

    @Override
    public boolean isDone() {
        return false;
    }

    @Override
    public boolean iteration() {
        return false;
    }

    //这里完成的是迭代的功能，迭代期间需要做什么处理，逻辑由外部传递进来
    boolean processAll(@NotNull Processor<? super PsiFile> processor) {
        VirtualFileSet visited = VfsUtilCore.createCompactVirtualFileSet();
        for (VirtualFile root : myRoots) {
            //逐个访问root【file、dir、dir or file in dir】中的元素
            boolean success = ProjectRootManager.getInstance(myProject).getFileIndex().iterateContentUnderDirectory(root, fileOrDir -> {
                //如果当前访问的虚拟文件是dir，并且已经存在访问记录了，直接返回
                if (fileOrDir.isDirectory() || !visited.add(fileOrDir)) {
                    return true;
                }
                PsiFile psiFile = ReadAction.compute(() -> myProject.isDisposed() ? null : PsiManager.getInstance(myProject).findFile(fileOrDir));
                //断路器
                return psiFile == null || !CommonUtils.shouldAddGen(psiFile) || processor.process(psiFile);
            });
            if (!success) return false;
        }
        return true;
    }
}
